home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * Adap_iso.c - adaptive isoline surface extraction algorithm. *
- *******************************************************************************
- * Written by Gershon Elber, Aug. 92. *
- ******************************************************************************/
-
- #include "symb_loc.h"
-
- #define SIMILAR_PARAM_VAL 1e-4
-
- #define CONVEX_BLEND(v1, v2, b1, b2, t) { \
- CagdRType \
- Blend = -b1 / ( b2 - b1 ); \
- t = v2 * Blend + v1 * (1.0 - Blend); \
- }
-
- static int MinSubdivLevel = 1;
-
- static CagdCrvStruct *SymbAdapIsoExtractAux(int Level,
- CagdSrfStruct *Srf,
- CagdSrfStruct *NSrf,
- SymbAdapIsoDistSqrFuncType
- AdapIsoDistFunc,
- CagdCrvStruct *Crv1,
- CagdCrvStruct *NCrv1,
- CagdCrvStruct *Crv2,
- CagdCrvStruct *NCrv2,
- CagdRType Crv1Param,
- CagdRType Crv2Param,
- CagdSrfDirType Dir,
- CagdRType Eps2,
- CagdBType FullIso,
- CagdBType SinglePath);
- static CagdCrvStruct *CopyRegionFromCrv(CagdCrvStruct *Crv,
- CagdRType TMin,
- CagdRType TMax);
- static CagdRType ComputeMidParam(CagdRType Param1,
- CagdRType Param2,
- CagdSrfDirType Dir,
- CagdSrfStruct *Srf);
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Sets minimum level of subdivision forced in the adaptive iso extraction. M
- * *
- * PARAMETERS: M
- * MinLevel: At least that many subdivision will occur. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * SymbSetAdapIsoExtractMinLevel, adaptive isocurves M
- *****************************************************************************/
- void SymbSetAdapIsoExtractMinLevel(int MinLevel)
- {
- MinSubdivLevel = MinLevel;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Extracts a valid coverage set of isolines from the given surface in the M
- * given direction and epsilon. M
- * If FullIso is TRUE, all extracted isocurves are spanning the entire M
- * parametric domain. M
- * If SinglePath is TRUE, the entire coverage is going to be a single M
- * curve. M
- * If NSrf != NULL, every second curve will be a vector field curve M
- * representing the unnormalized normal for the previous Euclidean curve. M
- * This mode disable the SinglePath mode. M
- * See also function SymbSetAdapIsoExtractMinLevel. M
- * *
- * PARAMETERS: M
- * Srf: To compute adaptive isocurve coverage form M
- * NSrf: Normal vector field defining the normals of Srf. M
- * AdapIsoDistFunc: Optional function to invoke with the two adjacent M
- * isoparametric curves of the coverage to evaluate the M
- * distance between them. M
- * Dir: Direction of adaptive isocurve extraction. Either U or V. M
- * Eps: Tolerance of adaptive isocurve cuverage. For every point P M
- * on Srf there will be a point Q in one of the extracted M
- * isocurves such the |P - Q| < Eps. M
- * FullIso: Do we want all isocurves to span the entire domain? M
- * SinglePath: Do we want a single curve through them all? M
- * *
- * RETURN VALUE: M
- * CagdCrvStruct *: A list of curves representing the computed adaptive M
- * isocurve coverage for surface Srf. If normal field, M
- * NSrf, is prescribed, normal curves are concatenated M
- * alternatingly in this list. M
- * *
- * KEYWORDS: M
- * SymbAdapIsoExtract, adaptive isocurves M
- *****************************************************************************/
- CagdCrvStruct *SymbAdapIsoExtract(CagdSrfStruct *Srf,
- CagdSrfStruct *NSrf,
- SymbAdapIsoDistSqrFuncType AdapIsoDistFunc,
- CagdSrfDirType Dir,
- CagdRType Eps,
- CagdBType FullIso,
- CagdBType SinglePath)
- {
- CagdBType
- SrfBezier = FALSE;
- CagdRType Crv1Param, Crv2Param;
- CagdCrvStruct *Crv1, *Crv2, *NCrv1, *NCrv2, *AllAdapIso, *TCrv;
-
- if (NSrf != NULL)
- SinglePath = FALSE;
-
- switch (Srf -> GType) {
- case CAGD_SBEZIER_TYPE:
- Srf = CnvrtBezier2BsplineSrf(Srf);
- SrfBezier = TRUE;
- break;
- case CAGD_SBSPLINE_TYPE:
- break;
- default:
- SYMB_FATAL_ERROR(SYMB_ERR_WRONG_SRF);
- break;
- }
-
- switch (Dir) {
- case CAGD_CONST_U_DIR:
- Crv1Param = Srf -> GType == CAGD_SBSPLINE_TYPE ?
- Srf -> UKnotVector[0] + EPSILON : EPSILON;
- Crv2Param = Srf -> GType == CAGD_SBSPLINE_TYPE ?
- Srf -> UKnotVector[Srf -> ULength +
- Srf -> UOrder - 1] - EPSILON
- : 1.0 - EPSILON;
- break;
- case CAGD_CONST_V_DIR:
- Crv1Param = Srf -> GType == CAGD_SBSPLINE_TYPE ?
- Srf -> VKnotVector[0] + EPSILON : EPSILON;
- Crv2Param = Srf -> GType == CAGD_SBSPLINE_TYPE ?
- Srf -> VKnotVector[Srf -> VLength +
- Srf -> VOrder - 1] - EPSILON
- : 1.0 - EPSILON;
- break;
- default:
- SYMB_FATAL_ERROR(SYMB_ERR_DIR_NOT_CONST_UV);
- Crv1Param = 0.0;
- Crv2Param = 1.0;
- break;
- }
-
- Crv1 = CagdCrvFromSrf(Srf, Crv1Param, Dir);
- Crv2 = CagdCrvFromSrf(Srf, Crv2Param, Dir);
- if (NSrf != NULL) {
- NCrv1 = CagdCrvFromSrf(NSrf, Crv1Param, Dir);
- NCrv2 = CagdCrvFromSrf(NSrf, Crv2Param, Dir);
- }
- else
- NCrv1 = NCrv2 = NULL;
-
- /* Compute the adaptive iso curves. */
- AllAdapIso = SymbAdapIsoExtractAux(0, Srf, NSrf, AdapIsoDistFunc,
- Crv1, NCrv1, Crv2, NCrv2,
- Crv1Param, Crv2Param,
- Dir, Eps * Eps, FullIso, SinglePath);
-
- /* Chain first and last iso curves that always span the entire domain. */
- if (AllAdapIso != NULL) {
- Crv1 -> Pnext = AllAdapIso;
- TCrv = CagdListLast(AllAdapIso);
- TCrv -> Pnext = Crv2;
- }
- else
- Crv1 -> Pnext = Crv2;
-
- if (NSrf != NULL) {
- NCrv1 -> Pnext = Crv1 -> Pnext;
- Crv1 -> Pnext = NCrv1;
- NCrv2 -> Pnext = Crv2 -> Pnext;
- Crv2 -> Pnext = NCrv2;
- }
-
- if (SrfBezier)
- CagdSrfFree(Srf);
-
- return Crv1;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * An auxiliary function of SymbAdapIsoExtract. Computes the distance square *
- * between the given two curves, extract the regions that are far than that *
- * and recursively invoke this function with the sub-curves. *
- * *
- * PARAMETERS: *
- * Level: Of recursion. *
- * Srf: This adaptive isocurve coverage is computed for. *
- * NSrf: Normal vectorfield of Srf. *
- * AdapIsoDistFunc: Optional function to invoke with the two adjacent *
- * isoparametric curves of the coverage to evaluate the *
- * distance between them. *
- * Crv1: First curve to handle. *
- * NCrv1: Normal vector field of first curve Crv1. *
- * Crv2: Second curve to handle. *
- * NCrv2: Normal vector field of second curve Crv2. *
- * Crv1Param: Parameter along the other direction of Srf, of Crv1. *
- * Crv2Param: Parameter along the other direction of Srf, of Crv2. *
- * Dir: Direction of adaptive isocurve extraction. *
- * Eps2: Tolerance of adaptive isocurve extraction. *
- * FullIso: Do we want all isocurves to span all parametric domain? *
- * SinglePath: Do we want everything in a single path? *
- * *
- * RETURN VALUE: *
- * CagdCrvStruct *: A list of isocurves covering Srf to within Eps2. *
- *****************************************************************************/
- static CagdCrvStruct *SymbAdapIsoExtractAux(int Level,
- CagdSrfStruct *Srf,
- CagdSrfStruct *NSrf,
- SymbAdapIsoDistSqrFuncType
- AdapIsoDistFunc,
- CagdCrvStruct *Crv1,
- CagdCrvStruct *NCrv1,
- CagdCrvStruct *Crv2,
- CagdCrvStruct *NCrv2,
- CagdRType Crv1Param,
- CagdRType Crv2Param,
- CagdSrfDirType Dir,
- CagdRType Eps2,
- CagdBType FullIso,
- CagdBType SinglePath)
- {
- int i, KVLen;
- CagdPointType PType;
- CagdRType Dist, *KV, LastT, DistCrv2Min, DistCrv2Max,
- **Points, *PtsW, *PtsX, LastDist,
- *Nodes = NULL;
- CagdBType CloseEnough, LastCloseEnough;
- CagdCrvStruct *TCrv, *DistCrv2,
- *AllAdapIsoTail = NULL,
- *AllAdapIso = NULL;
-
- if (AdapIsoDistFunc != NULL) { /* Call function to compute distance sqr. */
- DistCrv2 = AdapIsoDistFunc(Level, Crv1, NCrv1, Crv2, NCrv2);
- }
- else { /* Symbolically compute the distance square function. */
- CagdCrvStruct
- *DiffCrv = SymbCrvSub(Crv1, Crv2);
-
- DistCrv2 = SymbCrvDotProd(DiffCrv, DiffCrv);
- CagdCrvFree(DiffCrv);
- }
- PType = DistCrv2 -> PType;
-
- /* Simple heuristic how much to refine DistCrv2: */
- KVLen = DistCrv2 -> Length * 2;
- DistCrv2Min = DistCrv2 -> KnotVector[0];
- DistCrv2Max = DistCrv2 -> KnotVector[DistCrv2 -> Order +
- DistCrv2 -> Length - 1];
- KV = (CagdRType *) IritMalloc(sizeof(CagdRType) * KVLen);
- for (i = 0; i < KVLen; i++)
- KV[i] = DistCrv2Min + (i + 1) * (DistCrv2Max - DistCrv2Min) /
- (KVLen + 1);
-
- TCrv = BspCrvKnotInsertNDiff(DistCrv2, FALSE, KV, KVLen);
- IritFree((VoidPtr) KV);
- CagdCrvFree(DistCrv2);
- DistCrv2 = TCrv;
-
- Nodes = CagdCrvNodes(DistCrv2);
- LastT = Nodes[0];
- Points = DistCrv2 -> Points,
- PtsW = Points[W],
- PtsX = Points[X],
- LastDist = (PType == CAGD_PT_E1_TYPE ? PtsX[0]
- : (PtsX[0] / PtsW[0])) - Eps2;
- LastCloseEnough = LastDist < 0.0 && MinSubdivLevel <= Level;
-
- for (i = 1; i < DistCrv2 -> Length; i++) {
- Dist = (PType == CAGD_PT_E1_TYPE ? PtsX[i]
- : (PtsX[i] / PtsW[i])) - Eps2;
- CloseEnough = Dist < 0.0 && MinSubdivLevel <= Level;
-
- if (CloseEnough != LastCloseEnough ||
- (i == DistCrv2 -> Length - 1 && !LastCloseEnough)) {
- CagdRType t;
- int KnotIndex,
- KVLength = Crv1 -> Length + Crv1 -> Order;
-
- if (CloseEnough == LastCloseEnough)
- t = Nodes[DistCrv2 -> Length - 1];
- else
- CONVEX_BLEND(Nodes[i - 1], Nodes[i], LastDist, Dist, t);
-
- /* If parameter t is close "enough" to an existing knot. use it. */
- KnotIndex = BspKnotLastIndexLE(Crv1 -> KnotVector, KVLength, t);
- if (KnotIndex >= 0 &&
- t - Crv1 -> KnotVector[KnotIndex] < SIMILAR_PARAM_VAL)
- t = Crv1 -> KnotVector[KnotIndex];
- KnotIndex = BspKnotFirstIndexG(Crv1 -> KnotVector, KVLength, t);
- if (KnotIndex < KVLength &&
- Crv1 -> KnotVector[KnotIndex] - t < SIMILAR_PARAM_VAL)
- t = Crv1 -> KnotVector[KnotIndex];
-
- if (t - LastT > SIMILAR_PARAM_VAL &&
- (CloseEnough ||
- (i == DistCrv2 -> Length - 1 && !LastCloseEnough))) {
- /* We are at the end of a region that is not close enough. */
- if (SinglePath) {
- CagdRType
- MidParam1 = (Crv1Param * 2.0 + Crv2Param) / 3.0,
- MidParam2 = (Crv1Param + Crv2Param * 2.0) / 3.0;
- CagdCrvStruct
- *AdapIso1, *AdapIso2, *AdapIso3, *AdapIso,
- *MidCrv1 = CagdCrvFromSrf(Srf, MidParam1, Dir),
- *MidCrv2 = CagdCrvFromSrf(Srf, MidParam2, Dir);
-
- if (FullIso) {
- AdapIso1 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- Crv1, NULL,
- MidCrv1, NULL,
- Crv1Param, MidParam1,
- Dir, Eps2,
- FullIso, SinglePath);
- AdapIso2 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- MidCrv1, NULL,
- MidCrv2, NULL,
- MidParam1, MidParam2,
- Dir, Eps2,
- FullIso, SinglePath);
- AdapIso3 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- MidCrv2, NULL,
- Crv2, NULL,
- MidParam2, Crv2Param,
- Dir, Eps2,
- FullIso, SinglePath);
-
- if (AdapIso1 != NULL) {
- for (TCrv = AdapIso1;
- TCrv -> Pnext != NULL;
- TCrv = TCrv -> Pnext);
- TCrv -> Pnext = MidCrv1;
- AdapIso = AdapIso1;
- }
- else
- AdapIso = MidCrv1;
- if (AdapIso2 != NULL)
- MidCrv1 -> Pnext = AdapIso2;
-
- if (AdapIso2 != NULL) {
- for (TCrv = AdapIso2;
- TCrv -> Pnext != NULL;
- TCrv = TCrv -> Pnext);
- TCrv -> Pnext = MidCrv2;
- }
- else
- MidCrv1 -> Pnext = MidCrv2;
- if (AdapIso2 != NULL)
- MidCrv2 -> Pnext = AdapIso3;
-
- /* Chain these isolines to the entire set.*/
- if (AllAdapIso)
- AllAdapIsoTail -> Pnext = AdapIso;
- else
- AllAdapIso = AdapIso;
-
- for (AllAdapIsoTail = MidCrv2;
- AllAdapIsoTail -> Pnext != NULL;
- AllAdapIsoTail = AllAdapIsoTail -> Pnext);
-
- break; /* Only one (entire domain) region! */
- }
- else {
- CagdCrvStruct *Region1, *Region2,
- *MidRegion1, *MidRegion2;
-
- Region1 = CopyRegionFromCrv(Crv1, LastT, t),
- Region2 = CopyRegionFromCrv(Crv2, LastT, t);
- MidRegion1 = CopyRegionFromCrv(MidCrv1, LastT, t);
- MidRegion2 = CopyRegionFromCrv(MidCrv2, LastT, t);
- CagdCrvFree(MidCrv1);
- CagdCrvFree(MidCrv2);
-
- AdapIso1 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- Region1, NULL,
- MidRegion1, NULL,
- Crv1Param, MidParam1,
- Dir, Eps2,
- FullIso, SinglePath);
- AdapIso2 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- MidRegion1, NULL,
- MidRegion2, NULL,
- MidParam1, MidParam2,
- Dir, Eps2,
- FullIso, SinglePath);
- AdapIso3 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- MidRegion2, NULL,
- Region2, NULL,
- MidParam2, Crv2Param,
- Dir, Eps2,
- FullIso, SinglePath);
-
- if (AdapIso1 != NULL) {
- for (TCrv = AdapIso1;
- TCrv -> Pnext != NULL;
- TCrv = TCrv -> Pnext);
- TCrv -> Pnext = MidRegion1;
- AdapIso = AdapIso1;
- }
- else
- AdapIso = MidRegion1;
- if (AdapIso2 != NULL)
- MidRegion1 -> Pnext = AdapIso2;
-
- if (AdapIso2 != NULL) {
- for (TCrv = AdapIso2;
- TCrv -> Pnext != NULL;
- TCrv = TCrv -> Pnext);
- TCrv -> Pnext = MidRegion2;
- }
- else
- MidRegion1 -> Pnext = MidRegion2;
- if (AdapIso2 != NULL)
- MidRegion2 -> Pnext = AdapIso3;
-
- /* Chain these isolines to the entire set.*/
- if (AllAdapIso)
- AllAdapIsoTail -> Pnext = AdapIso;
- else
- AllAdapIso = AdapIso;
-
- for (AllAdapIsoTail = MidRegion2;
- AllAdapIsoTail -> Pnext != NULL;
- AllAdapIsoTail = AllAdapIsoTail -> Pnext);
- }
- }
- else { /* Return all the isocurves as a list of curves. */
- CagdRType
- MidParam = ComputeMidParam(Crv1Param, Crv2Param,
- Dir, Srf);
- CagdCrvStruct *AdapIso1, *AdapIso2, *AdapIso,
- *MidCrv = CagdCrvFromSrf(Srf, MidParam, Dir),
- *MidNCrv = NSrf ? CagdCrvFromSrf(NSrf, MidParam, Dir)
- : NULL;
-
- if (FullIso) {
- AdapIso1 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- Crv1, NCrv1,
- MidCrv, MidNCrv,
- Crv1Param, MidParam,
- Dir, Eps2,
- FullIso, SinglePath);
- AdapIso2 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- MidCrv, MidNCrv,
- Crv2, NCrv2,
- MidParam, Crv2Param,
- Dir, Eps2,
- FullIso, SinglePath);
-
- if (AdapIso1 != NULL) {
- for (TCrv = AdapIso1;
- TCrv -> Pnext != NULL;
- TCrv = TCrv -> Pnext);
- TCrv -> Pnext = MidCrv;
- AdapIso = AdapIso1;
- }
- else
- AdapIso = MidCrv;
-
- if (NSrf != NULL) {
- MidCrv -> Pnext = MidNCrv;
- MidCrv = MidNCrv;
- }
-
- if (AdapIso2 != NULL)
- MidCrv -> Pnext = AdapIso2;
-
- /* Chain these isolines to the entire set.*/
- if (AllAdapIso)
- AllAdapIsoTail -> Pnext = AdapIso;
- else
- AllAdapIso = AdapIso;
-
- for (AllAdapIsoTail = MidCrv;
- AllAdapIsoTail -> Pnext != NULL;
- AllAdapIsoTail = AllAdapIsoTail -> Pnext);
-
- break; /* Only one (entire domain) region! */
- }
- else {
- CagdCrvStruct *Region1, *Region2, *MidRegion,
- *NRegion1 = NULL,
- *NRegion2 = NULL,
- *MidNRegion = NULL;
-
- Region1 = CopyRegionFromCrv(Crv1, LastT, t);
- Region2 = CopyRegionFromCrv(Crv2, LastT, t);
- MidRegion = CopyRegionFromCrv(MidCrv, LastT, t);
- if (NSrf) {
- NRegion1 = CopyRegionFromCrv(NCrv1, LastT, t);
- NRegion2 = CopyRegionFromCrv(NCrv2, LastT, t);
- MidNRegion = CopyRegionFromCrv(MidNCrv, LastT,
- t);
- CagdCrvFree(MidNCrv);
- }
- CagdCrvFree(MidCrv);
-
- AdapIso1 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- Region1, NRegion1,
- MidRegion, MidNRegion,
- Crv1Param, MidParam,
- Dir, Eps2,
- FullIso, SinglePath);
- AdapIso2 = SymbAdapIsoExtractAux(Level + 1, Srf, NSrf,
- AdapIsoDistFunc,
- MidRegion, MidNRegion,
- Region2, NRegion2,
- MidParam, Crv2Param,
- Dir, Eps2,
- FullIso, SinglePath);
-
- if (AdapIso1 != NULL) {
- for (TCrv = AdapIso1;
- TCrv -> Pnext != NULL;
- TCrv = TCrv -> Pnext);
- TCrv -> Pnext = MidRegion;
- AdapIso = AdapIso1;
- }
- else
- AdapIso = MidRegion;
-
- if (NSrf != NULL) {
- MidRegion -> Pnext = MidNRegion;
- MidRegion = MidNRegion;
- }
-
- if (AdapIso2 != NULL)
- MidRegion -> Pnext = AdapIso2;
-
- CagdCrvFree(Region1);
- CagdCrvFree(Region2);
- if (NSrf != NULL) {
- CagdCrvFree(NRegion1);
- CagdCrvFree(NRegion2);
- }
-
- /* Chain these isolines to the entire set.*/
- if (AllAdapIso)
- AllAdapIsoTail -> Pnext = AdapIso;
- else
- AllAdapIso = AdapIso;
-
- for (AllAdapIsoTail = MidRegion;
- AllAdapIsoTail -> Pnext != NULL;
- AllAdapIsoTail = AllAdapIsoTail -> Pnext);
- }
- }
- }
-
- /* We are at the beginning of a region not close enough. */
- LastT = t;
- }
-
- LastDist = Dist;
- LastCloseEnough = CloseEnough;
- }
-
- CagdCrvFree(DistCrv2);
- IritFree((VoidPtr) Nodes);
-
- if (SinglePath) { /* Add connecting isocurves into the existing curves. */
- /* Not implemented yet. */
- }
-
- return AllAdapIso;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Extracts a sub region of the given curve, but also copies its attributes.*
- * *
- * PARAMETERS: *
- * Crv: To extracts a region from. *
- * TMin, TMax: Domain of region. *
- * *
- * RETURN VALUE: *
- * CagdCrvStruct *: Extracted region. *
- *****************************************************************************/
- static CagdCrvStruct *CopyRegionFromCrv(CagdCrvStruct *Crv,
- CagdRType TMin,
- CagdRType TMax)
- {
- CagdCrvStruct
- *Region = CagdCrvRegionFromCrv(Crv, TMin, TMax);
-
- Region -> Attr = AttrCopyAttributes(Crv -> Attr);
-
- return Region;
- }
-
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Estimates a parameter between Param1 and Param2 inSrf in Dir. Selects *
- * interior knots before selecting an average between parameters. *
- * *
- * PARAMETERS: *
- * Param1, Param2: Two parameters to find in between. *
- * Dir: Direction in Srf of Param1/2. *
- * Srf: Surface to explore. *
- * *
- * RETURN VALUE: *
- * CagdRType: A parameter between Param1 and Param2. *
- *****************************************************************************/
- static CagdRType ComputeMidParam(CagdRType Param1,
- CagdRType Param2,
- CagdSrfDirType Dir,
- CagdSrfStruct *Srf)
- {
- CagdRType t, *KV;
- int KVLen, Index1, Index2;
-
- switch (Dir) {
- case CAGD_CONST_U_DIR:
- KV = Srf -> UKnotVector;
- KVLen = Srf -> UOrder + Srf -> ULength;
- break;
- case CAGD_CONST_V_DIR:
- KV = Srf -> VKnotVector;
- KVLen = Srf -> VOrder + Srf -> VLength;
- break;
- default:
- SYMB_FATAL_ERROR(SYMB_ERR_DIR_NOT_CONST_UV);
- KV = NULL;
- KVLen = 0;
- }
-
- Index1 = BspKnotLastIndexLE(KV, KVLen, Param1);
- Index2 = BspKnotLastIndexLE(KV, KVLen, Param2);
-
- if (Index1 < 0 || Index2 < 0 || Index1 >= KVLen || Index2 >= KVLen) {
- SYMB_FATAL_ERROR(SYMB_ERR_OUT_OF_RANGE);
- return -INFINITY;
- }
-
- t = KV[(Index1 + Index2) / 2];
- if (t < Param1 || t > Param2 || APX_EQ(t, Param1) || APX_EQ(t, Param2))
- t = (Param1 + Param2) / 2.0;
-
- return t;
- }
-
-